using System;
using System.Security;
using System.Security.Cryptography;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.Globalization;
using System.Reflection;
using System.IO;

using WebServer;

namespace WebServer.Modules
{
	[CoreModule("Directory Registry", typeof(DirectoryRegistry), CoreModulePriority.Highest)]
	public class DirectoryRegistry
	{
		[Flags]
		public enum Options : byte
		{
			None = 0x00000000,
			Ensure = 0x00000001,
			Truncate = 0x00000002,
			PreserveStruct = 0x00000004,
			Replace = 0x00000008
		}

		public static string[] EnsurePaths = new string[] { "\\WebServer\\cache\\", "\\WebServer\\HTDOCS\\", "\\WebServer\\logs\\" };
		public static string BaseDirectory { get { return IOUtility.GetSafeDirectoryPath(Core.BaseDirectory); } }

		private static Dictionary<string, DirectoryInfo> _Registry = new Dictionary<string, DirectoryInfo>();
		public static Dictionary<string, DirectoryInfo> Registry { get { return _Registry; } }

		private static void Start()
		{
			Register(BaseDirectory);

			for (int i = 0; i < EnsurePaths.Length; i++)
				Register(EnsurePaths[i]);
		}

		public static DirectoryInfo Register(string path)
		{
			return Register(path, Options.None);
		}

		public static DirectoryInfo Register(string path, Options options)
		{
			if (path.StartsWith("\\") || path.StartsWith("/"))
				path = Core.BaseDirectory + path;

			string safePath = IOUtility.GetSafeDirectoryPath(path);

			if (String.IsNullOrEmpty(safePath))
				return null;

			DirectoryInfo di = (options & Options.Ensure) != 0 ?
				IOUtility.EnsureDirectory(safePath, (options & Options.Replace) != 0) : new DirectoryInfo(safePath);

			if (di != null && di.Exists)
			{
				if ((options & Options.Truncate) != 0)
					IOUtility.EmptyDirectory(di, !((options & Options.PreserveStruct) != 0));

				if (!_Registry.ContainsKey(safePath) && (options & Options.Replace) != 0)
					_Registry[safePath] = di;
				else
					_Registry.Add(safePath, di);

				return di;
			}

			return null;
		}

		public static DirectoryInfo GetDirectory(string path)
		{
			return GetDirectory(path, Options.None);
		}

		public static DirectoryInfo GetDirectory(string path, Options options)
		{
			if (path.StartsWith("\\") || path.StartsWith("/"))
				path = Core.BaseDirectory + path;

			string safePath = IOUtility.GetSafeDirectoryPath(path);

			if (String.IsNullOrEmpty(safePath))
				return null;

			DirectoryInfo di = null;

			if (_Registry.ContainsKey(safePath) && (options & Options.Replace) != 0)
				di = _Registry[safePath];
			else if ((options & Options.Ensure) != 0)
				di = Register(safePath, options);

			if ((options & Options.Truncate) != 0)
				IOUtility.EmptyDirectory(di, !((options & Options.PreserveStruct) != 0));

			return di;
		}

		public static FileInfo[] GetFiles(string mask)
		{
			string safeName = IOUtility.GetSafeFilePath(mask, true);

			if (String.IsNullOrEmpty(safeName))
				return null;

			List<FileInfo> files = new List<FileInfo>();

			foreach (DirectoryInfo info in _Registry.Values)
			{
				FileInfo[] f = info.GetFiles(safeName, SearchOption.AllDirectories);

				for (int i = 0; i < f.Length; i++)
				{
					if (!files.Contains(f[i]))
						files.Add(f[i]);
				}
			}

			return files.ToArray();
		}
	}
}